#include "MultiMatrix.h"
#include "RGBMatrix.h"

cMultiMatrix MultiMatrix;

void cMultiMatrix::begin(const unsigned int topLeftBoardIndex, const unsigned int topLeftFacing,
		const unsigned int topRightBoardIndex, const unsigned int topRightFacing,
		const unsigned int bottomRightBoardIndex, const unsigned int bottomRightFacing,
		const unsigned int bottomLeftBoardIndex, const unsigned int bottomLeftFacing) 
{
	_topLeftBoardIndex = topLeftBoardIndex;
	_topLeftFacing = topLeftFacing;

	_topRightBoardIndex = topRightBoardIndex;
	_topRightFacing = topRightFacing;

	_bottomRightBoardIndex = bottomRightBoardIndex;
	_bottomRightFacing = bottomRightFacing;

	_bottomLeftBoardIndex = bottomLeftBoardIndex;
	_bottomLeftFacing = bottomLeftFacing;

	RGBMatrix.begin(4);
}

cMultiMatrix::PixelData cMultiMatrix::_getPixelDataForCoords(const unsigned int rowIndex, const unsigned int columnIndex)
{
	if (rowIndex > MULTI_NUM_ROWS) 
	{
		// I'm not sure what will happen if Serial isn't initialized
		Serial.print("warning: rowIndex out of bounds: ");
		Serial.println(rowIndex);
	}

	if (columnIndex > MULTI_NUM_COLUMNS)
	{
		Serial.print("warning: columnIndex out of bounds: ");
		Serial.println(columnIndex);
	}

	cMultiMatrix::PixelData result = _getScreenForCoords(rowIndex, columnIndex);

	if ((result.screenIndex == _topLeftBoardIndex && _topLeftFacing == SOUTH)
		|| (result.screenIndex == _topRightBoardIndex && _topRightFacing == SOUTH)
		|| (result.screenIndex == _bottomRightBoardIndex && _bottomRightFacing == SOUTH)
		|| (result.screenIndex == _bottomLeftBoardIndex && _bottomLeftFacing == SOUTH))
	{
		// If the board is south, we need to flip the indices (so 3, 3 becomes 5, 5; etc)
		cMultiMatrix::PixelData flippedResult = {result.screenIndex, NUM_ROWS - 1 - result.rowIndex, NUM_COLUMNS - 1- result.columnIndex};
		return flippedResult;
	}

	return result;
}

cMultiMatrix::PixelData cMultiMatrix::_getScreenForCoords(const unsigned int rowIndex, const unsigned int columnIndex)
{
	if (rowIndex < NUM_ROWS) 
	{
		if (columnIndex < NUM_COLUMNS)
		{
			cMultiMatrix::PixelData result = { _topLeftBoardIndex, rowIndex, columnIndex};
			return result;
		}

		cMultiMatrix::PixelData result = { _topRightBoardIndex, rowIndex, columnIndex - NUM_COLUMNS};
		return result;
	}

	if (columnIndex < NUM_COLUMNS)
	{
		cMultiMatrix::PixelData result = { _bottomLeftBoardIndex, rowIndex - NUM_ROWS, columnIndex};
		return result;
	}

	cMultiMatrix::PixelData result = { _bottomRightBoardIndex, rowIndex - NUM_ROWS, columnIndex - NUM_COLUMNS};
	return result;
}

char cMultiMatrix::fillPixel(int row, int column, char color) {
	cMultiMatrix::PixelData pixel = _getPixelDataForCoords(row, column);
	return RGBMatrix.fillPixel(pixel.screenIndex, pixel.rowIndex, pixel.columnIndex, color);
}

char cMultiMatrix::fillColumn(int column, char color)
{
	cMultiMatrix::PixelData firstScreenPixel = _getPixelDataForCoords(0, column);
	cMultiMatrix::PixelData secondScreenPixel = _getPixelDataForCoords(NUM_ROWS, column);

	return RGBMatrix.fillColumn(firstScreenPixel.screenIndex, firstScreenPixel.columnIndex, color) 
		&& RGBMatrix.fillColumn(secondScreenPixel.screenIndex, secondScreenPixel.columnIndex, color);
}

char cMultiMatrix::fillRow(int row, char color)
{
	cMultiMatrix::PixelData firstScreenPixel = _getPixelDataForCoords(row, 0);
	cMultiMatrix::PixelData secondScreenPixel = _getPixelDataForCoords(row, NUM_COLUMNS);

	return RGBMatrix.fillRow(firstScreenPixel.screenIndex, firstScreenPixel.rowIndex, color) && RGBMatrix.fillRow(secondScreenPixel.screenIndex, secondScreenPixel.rowIndex, color);
}

char cMultiMatrix::fillScreen(char color)
{
	return RGBMatrix.fillScreen(_topLeftBoardIndex, color) &&
			RGBMatrix.fillScreen(_topRightBoardIndex, color) &&
			RGBMatrix.fillScreen(_bottomLeftBoardIndex, color) &&
			RGBMatrix.fillScreen(_bottomRightBoardIndex, color);
}

void cMultiMatrix::display(void) {
	RGBMatrix.display();
}

void cMultiMatrix::clear(void) {
	RGBMatrix.clear();
}
